/***********************************************************************************
 * 文件名： soft_uart.c
 * 版本�?1
 * 说明�?
 * 		软件模拟UART。提供单个字节发送和接收的基本功能，类似于常见MCU的基础UART外设�?
 *      通过定时器中断中调用 SUart_EvTimer 来定时查询IO状态进行接收，定时控制IO状态进行发送�?
 *      在头文件中查看其�?API 以及说明�?
 * 修改记录�?
 * 	2021/04/28: 初版�?刘言�?
***********************************************************************************/
#include "cpt-soft_uart.h"
#include "polsys.h"

bit _SUart_Run;

static u8 SUart_mRxStep = 0; // 接收步骤
static u8 SUart_mRxCycCount; // 接收1个位的时钟周期计�?
static u8 SUart_mRxBitCount; // 接收位计�?
volatile u8 _SUart_mRxBuff;  // 接收缓存

volatile bit _SUart_mSending;
static u8 SUart_mTxStep;     // 发送步�?
static u8 SUart_mTxBuff;     // 发送缓�?
static u8 SUart_mTxBitCount; // 发送位计数
static u8 SUart_mTxCycCount; // 发�?个位的时钟周期计�?

// 声明引用事件通知函数（避免使用函数指针的妥协�?
// 在你的应用代码中定义这个函数用于接收事件
void SUart_Event(suart_ev_t e);

void SUart_EvTimer()
{
    if (_SUart_Run)
    {
#ifdef _SUART_HALF_DUPLEX
        if (!_SUart_mSending)
#endif
        {
            if (SUart_mRxStep == 0) // 等待高电�?
            {
                if (_SUart_GetRxPin())
                {
                    SUart_mRxStep = 1;
                }
            }
            else if (SUart_mRxStep == 1) // 等待低电平（第一次检测到的低电平是起始位刚跳变时候）
            {
                if (!_SUart_GetRxPin())
                {
                    SUart_mRxStep = 2;
                }
            }
            else if (SUart_mRxStep == 2) // 接收起始位（低电平，这个时刻正常来说处于起始位的中间周期�?
            {
                if (!_SUart_GetRxPin())
                {
                    SUart_mRxStep = 3;
                    SUart_mRxCycCount = 0;
                    SUart_mRxBitCount = 0;
                }
                else
                {
                    SUart_mRxStep = 1; // 起始位错误，重新等待低电�?
                }
            }
            else if (SUart_mRxStep == 3) // 接收数据
            {
                SUart_mRxCycCount++;
                if (SUart_mRxCycCount == 3)
                {
                    SUart_mRxCycCount = 0;
                    _SUart_mRxBuff >>= 1;
                    if (_SUart_GetRxPin())
                    {
                        _SUart_mRxBuff |= 0x80;
                    }
                    SUart_mRxBitCount++;

                    if (SUart_mRxBitCount == 8)
                    {
                        SUart_mRxStep = 4;
                        SUart_Event(SUART_EV_RX_DONE);
                    }
                }
            }
            else if (SUart_mRxStep == 4) // 接收停止位（高电平）
            {
                SUart_mRxCycCount++;

                if (_SUart_GetRxPin())
                {
                    SUart_mRxStep = 1; // 收到了停止位，重新等待低电平(这里有可能依然是最后一位高电平，因为SUart_Event执行时间可能较长会影响停止位的接收，所以没有严格等�?个时钟周期�?
                }
                else if (SUart_mRxCycCount == 3)
                {
                    SUart_mRxStep = 0; // 停止位电平错误，重新等待高电平（如果SUart_Event处理时间大于3个时钟周期也会导致这个错误）
                    SUart_Event(SUART_EV_STOP_ERR);
                }
            }
            else
            {
                SUart_mRxStep = 0;
            }
        }
        if (_SUart_mSending)
        {
            SUart_mTxCycCount++;
            if (SUart_mTxCycCount == 3)
            {
                SUart_mTxCycCount = 0;
                if (SUart_mTxStep == 0) // 发送起始位
                {
                    _SUart_SetTxPin(0);
                    SUart_mTxStep = 1;
                }
                else if (SUart_mTxStep == 1) // 发送数�?
                {
                    _SUart_SetTxPin(SUart_mTxBuff & 0x01);
                    SUart_mTxBuff >>= 1;
                    SUart_mTxBitCount++;
                    if (SUart_mTxBitCount == 8)
                    {
                        SUart_mTxStep = 2;
                    }
                }
                else if (SUart_mTxStep == 2) // 发送结束位
                {
                    _SUart_SetTxPin(1);
                    SUart_mTxStep = 3;
                }
                else if (SUart_mTxStep == 3) // 发送完�?
                {
                    _SUart_mSending = false;
#ifdef _SUART_USE_TX_DONE_EVENT
                    SUart_Event(SUART_EV_TX_DONE);
#endif
#ifdef _SUART_HALF_DUPLEX
                    _SUart_PinRxMode();
#endif
                }
                else
                {
                    SUart_mTxStep = 0;
                }
            }
        }
    }
}

void SUart_SendByte(u8 byte)
{
#ifdef _SUART_HALF_DUPLEX
    _SUart_PinTxMode();
#endif
    SUart_mTxCycCount = 0;
    SUart_mTxBitCount = 0;
    SUart_mTxStep = 0;
    SUart_mTxBuff = byte;
    _SUart_mSending = true;
}
